﻿using Levfier.Proccessors.Parameters;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Levfier.GUI.EditorControls.Parameters
{
    /// <summary>
    /// ParameterSlider.xaml の相互作用ロジック
    /// </summary>
    [Serializable]
    public partial class ParameterSlider : UserControl, IParameterHolder
    {
        /// <summary>
        /// 値変更が行われたときに発生するイベントハンドラ
        /// </summary>
        public event RoutedPropertyChangedEventHandler<double> ValueChanged;

        /// <summary>
        /// いじる対象のプロセッサパラメータ
        /// </summary>
        public ProccessParameter ProccessParameter { get; set; }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public ParameterSlider()
        {
            InitializeComponent();
            this.parameterSlider.ValueChanged += this.Slider_ValueChanged;
        }

        /// <summary>
        /// パラメータを登録する
        /// </summary>
        /// <param name="param"></param>
        public void RegisterParam(ProccessParameter param)
        {
            this.parameterSlider.Maximum = param.MaxValue;
            this.parameterSlider.Minimum = param.MinValue;
            this.parameterSlider.SmallChange = param.Step;
            this.parameterSlider.Value = param.Value;
            param.ValueChanged += this.ProccessParameter_ValueChanged;
            this.parameterName.Text = param.Name;
            this.ProccessParameter = param;
        }

        /// <summary>
        /// パラメータの値が変更された時の動作
        /// </summary>
        /// <param name="sender"></param>
        private void ProccessParameter_ValueChanged(object sender)
        {
            if (null != this.parameterSlider)
            {
                //値が異なるときだけにしないとループする
                if (parameterSlider.Value != this.ProccessParameter.Value)
                {
                    //パラメータの値を見た目にスライダに反映する
                    parameterSlider.Value = this.ProccessParameter.Value;
                }
            }
        }

        /// <summary>
        /// スライダが変更された時の動作
        /// </summary>
        /// <param name="sender">イベント発生源</param>
        /// <param name="e">イベント</param>
        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            //刻みを適用する
            Slider slider = sender as Slider;
            if (null != slider)
            {
                double rounded = Math.Round((slider.Value - slider.Minimum) / slider.SmallChange) * slider.SmallChange + slider.Minimum;
                slider.Value = rounded;
                if (null != this.ProccessParameter)
                {
                    this.ProccessParameter.Value = rounded;
                }
            }

            if (null != this.ValueChanged)
            {
                this.ValueChanged(this, e);
            }
        }

        /// <summary>
        /// ダウンボタン押下時の動作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DownButton_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.parameterSlider.Value -= this.parameterSlider.SmallChange;
            this.Slider_ValueChanged(this.parameterSlider, null);
        }

        /// <summary>
        /// アップボタン押下時の動作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpButton_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            this.parameterSlider.Value += this.parameterSlider.SmallChange;
            this.Slider_ValueChanged(this.parameterSlider, null);
        }

        /// <summary>
        /// ドラッグ開始
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UserControl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            //マウスの左ボタンだけが押されている時のみドラッグできるようにする
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                DataObject dataObject = new DataObject(typeof(IParameterHolder), this);
                DragDrop.DoDragDrop(this, dataObject, DragDropEffects.Move);
            }
        }
    }
}
